#include "CH58x_common.h"
#include "zqm_global.h"
#include "hal_uart.h"

typedef volatile uint8_t * uint8vp_t;
ZqUartHandle zq_uart_handle[4] = { 0 };

#ifndef ZQ_SIMULATOR
static const uint8_t uart_irq_map[4] = { UART0_IRQn, UART1_IRQn, UART2_IRQn, UART3_IRQn };

void UartInit(uint8_t port, int baudrate, uint8_t *rx_buf, uint16_t rx_buf_size, void (*rx_cb)(uint8_t* data, uint16_t *len))
{
    switch(port) {
        case 0:
            GPIO_SetBits(zy_ios.uart0_tx);//TX0
            GPIO_ModeCfg(zy_ios.uart0_rx, GPIO_ModeIN_PU);
            GPIO_ModeCfg(zy_ios.uart0_tx, GPIO_ModeOut_PP_5mA);
            break;
        case 1:
            GPIO_SetBits(zy_ios.uart1_tx);//TX1
            GPIO_ModeCfg(zy_ios.uart1_rx, GPIO_ModeIN_PU);
            GPIO_ModeCfg(zy_ios.uart1_tx, GPIO_ModeOut_PP_5mA);
            break;
        case 2:
            GPIO_SetBits(zy_ios.uart2_tx);//TX2
            GPIO_ModeCfg(zy_ios.uart2_rx, GPIO_ModeIN_PU);
            GPIO_ModeCfg(zy_ios.uart2_tx, GPIO_ModeOut_PP_5mA);
            GPIOPinRemap(ENABLE, RB_PIN_UART2); // 目前硬件布局要切换到第二套uart2引脚
            break;
        case 3:
            GPIO_SetBits(zy_ios.uart3_tx);//TX3
            GPIO_ModeCfg(zy_ios.uart3_rx, GPIO_ModeIN_PU);
            GPIO_ModeCfg(zy_ios.uart3_tx, GPIO_ModeOut_PP_5mA);
            GPIOPinRemap(ENABLE, RB_PIN_UART3);  // 目前硬件布局要切换到第三套uart3引脚
            break;
        default:
            return;
    }
    zq_uart_handle[port].rx_buf = rx_buf;
    zq_uart_handle[port].rx_buf_size = rx_buf_size;
    zq_uart_handle[port].rx_buf_pos = 0;
    zq_uart_handle[port].rx_cb = rx_cb;

    uint8_t *reg_base = (uint8_t *)(0x40003000 + 0x400 * port);
    uint32_t x = 10 * GetSysClock() / 8 / baudrate;
    x = (x + 5) / 10;
    *(uint16_t *)(reg_base + 0x0c) = (uint16_t)x;

    *(reg_base + 0x02) = (UART_4BYTE_TRIG << 6) | RB_FCR_TX_FIFO_CLR | RB_FCR_RX_FIFO_CLR | RB_FCR_FIFO_EN; // R8_UARTx_FCR。FIFO打开，触发点4字节
    *(reg_base + 0x03) = RB_LCR_WORD_SZ;                                            // R8_UARTx_LCR
    *(reg_base + 0x01) = RB_IER_TXD_EN | RB_IER_RECV_RDY | RB_IER_LINE_STAT;        // R8_UARTx_IER
    *(reg_base + 0x0E) = 1;             // R8_UARTx_DIV
    *reg_base |= RB_MCR_INT_OE;         // R8_UARTx_MCR
    PFIC_EnableIRQ(uart_irq_map[port]);
    return;
}

__HIGH_CODE
static void UartIRQHandler(uint8_t port)
{
    uint8vp_t reg_base = (uint8vp_t)0x40003000 + 0x400 * port;
    uint8vp_t reg_iir = reg_base + 0x04;
    uint8vp_t reg_lSR = reg_base + 0x05;
    uint8vp_t reg_rbr = reg_base + 0x08;
    uint8vp_t reg_rfc = reg_base + 0x0A;

    // uint8_t tmp;
    uint8_t *buf = zq_uart_handle[port].rx_buf;
    uint16_t len = zq_uart_handle[port].rx_buf_pos;
    uint16_t size = zq_uart_handle[port].rx_buf_size;
    switch (*reg_iir & RB_IIR_INT_MASK)
    {
    case UART_II_RECV_RDY: // 数据达到设置触发点 4byte trig, 
        for(int i = 1; i < 4; i++) {
            if(len < size) buf[len++] = *reg_rbr;
            else *reg_rbr;        // buf溢出，读出放弃
        }
        zq_uart_handle[port].rx_buf_pos = len;
        break;
    case UART_II_RECV_TOUT: // 接收超时，一帧数据接收完成
        while(*reg_rfc) {
            if(len < size) buf[len++] = *reg_rbr;
            else *reg_rbr;        // buf溢出，读出放弃
        }
        zq_uart_handle[port].rx_buf_pos = len;
    
        if(zq_uart_handle[port].rx_cb)    // 如果用户给了回调函数，就是简单的调用户回调处理, 依赖串口帧机制分包, 且回调不能耗时太久。
            zq_uart_handle[port].rx_cb(buf, &(zq_uart_handle[port].rx_buf_pos));
        break;
    case UART_II_LINE_STAT: // 线路状态错误
        *reg_lSR;
        break;
    case UART_II_THR_EMPTY: // 发送缓存区空，可继续发送
    case UART_II_MODEM_CHG: // 只支持串口0
    default:
        break;
    }
}

void UartSend(uint8_t port, uint8_t *buf, uint16_t len)
{
    uint8vp_t reg_thr = (uint8vp_t)0x40003000 + 0x400 * port;
    uint8vp_t reg_tfc = reg_thr + 0x0B;
    reg_thr = reg_thr + 0x08;
    for(uint8_t *end = buf + len; buf < end; ){
        if(*reg_tfc != UART_FIFO_SIZE) *reg_thr = *buf++;
    }
}

void UartLock(uint8_t port)
{
    PFIC_DisableIRQ(uart_irq_map[port]);
}
void UartUnlock(uint8_t port)
{
    PFIC_EnableIRQ(uart_irq_map[port]);
}


__INTERRUPT
__HIGH_CODE
void UART0_IRQHandler(void)
{
    UartIRQHandler(0);
}
__INTERRUPT
__HIGH_CODE
void UART1_IRQHandler(void)
{
    UartIRQHandler(1);
}
__INTERRUPT
__HIGH_CODE
void UART2_IRQHandler(void)
{
    UartIRQHandler(2);
}
__INTERRUPT
__HIGH_CODE
void UART3_IRQHandler(void)
{
    UartIRQHandler(3);
}

#else // ZQ_SIMULATOR
#include "simu_mcu582.h"
void UartInit(uint8_t port, int baudrate, uint8_t* rx_buf, uint16_t rx_buf_size, void (*rx_cb)(uint8_t* data, uint16_t* len))
{
    SimuUartInit(port, baudrate, rx_buf, rx_buf_size, rx_cb);
}
void UartSend(uint8_t port, uint8_t* buf, uint16_t len)
{
    SimuUartSend(port, buf, len);
}
#endif // ZQ_SIMULATOR

int UartIfSwitchToFtm(uint8_t *data, uint16_t data_len)
{
#if (!ZQ_SIMULATOR) // 增加处理特别的ftm头部, 只针对port 1
    if (data_len >= 8)
    {
    const char ftm_head[] = { 0xaa, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
        if (memcmp(data, ftm_head, 8) == 0) {
            //[panzhimin] ftm code
            extern int8_t ftm_master_rx_handler(uint8_t * rx_buffer, uint16_t rx_length);
            ftm_master_rx_handler(data, data_len);
            // [panzhimin] ftm code end
            UartLock(1);    // 锁定(582上是关闭相应中断)
            zq_uart_handle[1].rx_buf_pos = 0;
            UartUnlock(1);    // 解锁(582上是打开相应中断)
            return 1;
        }
    }
#endif
    return 0;
}

void UartRecv(uint8_t port, void (*rx_cb)(ZqCommPkg* pkg))
{
#if (!ZQ_SIMULATOR)
    ZqUartHandle *puh = zq_uart_handle + port;
#else
    ZqSimuUartHandle *puh = zq_simu_uart_handle + port;
#endif
    uint8_t* data = puh->rx_buf;
    uint16_t buf_size = puh->rx_buf_size;
    uint16_t data_len = puh->rx_buf_pos;
    uint16_t step = 0;
    ZqCommPkg* pkg;

    if((port == 1) && (UartIfSwitchToFtm(data, data_len) == 1)) return;        // Port1口会有特别的FTM切换命令

    for (; step < data_len; step += pkg->len) {
        if ((data_len - step) < sizeof(ZqCommPkg)) return; // wait more data
        pkg = (ZqCommPkg*)(data + step);
        if (pkg->flag != COMM_PKG_HEAD_FLAG || pkg->len > buf_size || pkg->len < sizeof(ZqCommPkg)) {// 标志出错或长度出错, discard all data
            step = 0xffff;
            break;
        }
        if (pkg->len > (data_len - step)) return; // wait more data
        if (ZqGetChecksum(data, pkg->len) != 0) { // checksum error
            step = 0xffff;
            break;
        }
        rx_cb(pkg);
    }

    if (step > 0) { // there are discard data, need to djust the data pointer of receive buffer
        UartLock(port);    // 锁定(582上是关闭相应中断)
        if (step == 0xffff) { // 数据异常, clear receive buffer
            puh->rx_buf_pos = 0;
        }
        else {
            puh->rx_buf_pos -= step;
            memcpy(data, data + step, puh->rx_buf_pos);
        }
        UartUnlock(port);    // 解锁(582上是打开相应中断)
    }
}
